package tms.unitTests;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;


import static org.junit.Assert.*;


import org.junit.Before;
import org.junit.Test;

import tms.model.*;

/**
 * PeopleTableUnitTests class contains the units tests of the methods in PeopleTable class 
 * 
 * @author Amer Alhalabi
 *
 */
public class PeopleTableUnitTests {

	/// a header line used in converting a task to a string
	final String H_LINE = "---------------------------------------";
	/// a header line used in writing the people table to a csv file
	private static final String HEADER_STRING = "Name,Hours,Tasks\n";
	
	/**
	 * default constructor
	 */
	public PeopleTableUnitTests() {
    }
	
	/**
	 * helper method to write a string to a file
	 * 
	 * @param fileName the name of the file to be written to 
	 * @param content content to be writen to the file
	 */
	private void createFile( String fileName, String content) {
		PrintWriter printOut = null; 
		try {
			printOut = new PrintWriter(fileName); 
			printOut.print(content); 
			printOut.close();
		}
		catch (FileNotFoundException e) {
			System.out.println(e.getMessage());
		}
	}
	
	/**
	 * helper method to check if a file exists
	 * 
	 * @param fileName name of the file to be checked 
	 * 
	 * @return true if the file exists; false otherwise
	 */
	private boolean fileExists(String fileName) {
		if (fileName == null || fileName == "")
			return false;
		File file = new File(fileName);
		return file.exists();
	}
	
	/**
	 * helper method to delete a file
	 * 
	 * @param fileName the name of the file to be deleted
	 */
	private void deleteFile(String fileName) {
		File file = new File(fileName);
		file.delete();
	}
	
	/**
	 * helper method to load the content of a file into a string
	 * 
	 * @param filename name of the file whose content is to be loaded
	 * 
	 * @return a string containing the content of the file 
	 */
	private String loadFileContent(String filename) {
		byte[] buffer = new byte[(int) new File(filename).length()];
	    BufferedInputStream bufferedInStream = null;
	    try {
	    	bufferedInStream = new BufferedInputStream(new FileInputStream(filename));
	    	bufferedInStream.read(buffer);
	    } catch (IOException e) {
			e.printStackTrace();
		} finally {
	        if (bufferedInStream != null) try { bufferedInStream.close(); } catch (IOException ignored) { }
	    }
	    return new String(buffer);
	}
	
	/**
	 * helper method called before every unit test to clear the peopletable
	 */
	@Before
	public void setUp() {
		PeopleTable.getInstance().getPersonList().clear();
		PeopleTable.getInstance().getPersonMap().clear();
	}
	
	/**
	 * test that the only instance of the people table is not null 
	 * and that it contains no person object
	 */
	@Test
	public void testPeopleTableGetInstance1() {
       
		PeopleTable peopleTable = PeopleTable.getInstance();
		assertNotNull(peopleTable);
		assertTrue(peopleTable.getPersonList().isEmpty());
    }
	
	/**
	 * test that the getInstance() always returns the same intsance of the peopletable no matter how
	 * many times it is called
	 */
	@Test
	public void testPeopleTableGetInstance2() {
       
		PeopleTable peopleTable1 = PeopleTable.getInstance();
		PeopleTable peopleTable2 = PeopleTable.getInstance();
		PeopleTable peopleTable3 = PeopleTable.getInstance();
		
		assertNotNull(peopleTable1);
		assertSame(peopleTable1, peopleTable2);
		assertSame(peopleTable2, peopleTable3);
    }

	/**
	 *  test saving people table to an csv file where the filename is null
	 *  expect that no output file gets created
	 */
	@Test
	public void testPeopleTableSaveCSVFile1() {
		
		String filename = null;
		PeopleTable peopleTable = PeopleTable.getInstance();
		
		assertFalse(peopleTable.saveCSVFile(filename));
		assertFalse(fileExists(filename));
	}
	
	/**
	 *  test saving people table to an csv file where the filename is empty
	 *  expect that no output file gets created
	 */
	@Test
	public void testPeopleTableSaveCSVFile2() {
		
		String filename = "";
		PeopleTable peopleTable = PeopleTable.getInstance(); 
		
		assertFalse(peopleTable.saveCSVFile(filename));
		assertFalse(fileExists(filename));
	}
	
	/**
	 *  test saving people table to an csv file that already exists
	 *  expect that the content file to be overwritten 
	 */
	@Test
	public void testPeopleTableSaveCSVFile3() {
		
		// input and output filenames
		String infilename = "test.xml";
		String outFilename = "out.csv";
		
		// the content the input xml file
		// there are three tasks; two of which are assigned to the same person 
		String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 
		content += "<data>\n";
		content += "\t<task>\n";
		content += "\t\t<id>1</id>\n";
		content += "\t\t<title>Iteration 1</title>\n";
		content += "\t\t<description>des1</description>\n";
		content += "\t\t<duration>1</duration>\n";
		content += "\t\t<deliverable>del1</deliverable>\n";
		content += "\t\t<deadline>2012-01-27</deadline>\n";
		content += "\t\t<person>Person 1</person>\n";
		content += "\t</task>\n";
		
		content += "\t<task>\n";
		content += "\t\t<id>2</id>\n";
		content += "\t\t<title>Iteration 2</title>\n";
		content += "\t\t<description>des2</description>\n";
		content += "\t\t<duration>2</duration>\n";
		content += "\t\t<deliverable>del2</deliverable>\n";
		content += "\t\t<deadline>2012-01-27</deadline>\n";
		content += "\t\t<person>Person 2</person>\n";
		content += "\t</task>\n";
		
		content += "\t<task>\n";
		content += "\t\t<id>3</id>\n";
		content += "\t\t<title>Iteration 3</title>\n";
		content += "\t\t<description>des3</description>\n";
		content += "\t\t<duration>3</duration>\n";
		content += "\t\t<deliverable>del3</deliverable>\n";
		content += "\t\t<deadline>2012-01-27</deadline>\n";
		content += "\t\t<person>Person 1</person>\n";
		content += "\t</task>\n";
		content += "</data>\n";
		
		// create the input and output files
		createFile(infilename, content);
		createFile(outFilename, ""); 
		
		// load the input xml file into the tasktable
		// and expect successful loading of tasks
		TaskTable taskTable = TaskTable.getInstance();
		PeopleTable peopleTable = PeopleTable.getInstance();
		assertTrue(taskTable.openXMLFile(infilename));
		// expect that three tasks were loaded
		assertEquals(taskTable.getTaskList().size(), 3);
		// expect that two people were added to the people table 
		// as there are two tasks that are assigned to the person
		assertEquals(peopleTable.getPersonList().size(), 2);
		
		// save the people table to an CSV file
		// and expect successful operation
		assertTrue(peopleTable.saveCSVFile(outFilename));
		assertTrue(fileExists(outFilename));
		
		// compare the new content of the people CSV file with the expected one  
		String cont = loadFileContent(outFilename);
		String expected = "";
		expected += HEADER_STRING ;
		expected += "Person 1,4,\"1, 3\""; 
		expected += "\n";
		expected += "Person 2,2,\"2\""; 
		expected += "\n";
		System.out.println(cont);
		assertTrue(cont.equals(expected));
		
		// cleanup
		deleteFile(infilename);
		deleteFile(outFilename);
	}
	
	/**
	 *  test saving an empty people table to an csv file
	 *  expect that a csv file with only the file header will be created 
	 */
	@Test
	public void testPeopleTableSaveCSVFile4() {
		
		String filename = "test.csv";
		
		// this is an empty people table
		PeopleTable peopleTable = PeopleTable.getInstance();
		
		// test output csv file contains only the header string
		assertTrue(peopleTable.saveCSVFile(filename));
		assertTrue(fileExists(filename));
		String cont = loadFileContent(filename);
		assertTrue(cont.equals(HEADER_STRING));
		
		// clean up
		deleteFile(filename);
	}

	/**
	 *  test saving an people table that contains two person objects to an csv file
	 *  expect that an CSV file to be created with valid content
	 */
	@Test
	public void testPeopleTableSaveCSVFile5() {
		
		// input and output filenames
		String infilename = "test.xml";
		String outFilename = "out.csv";
		
		// create the content of the input xml file
		// there are three tasks; two of which are assigned to the same person
		String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 
		content += "<data>\n";
		content += "\t<task>\n";
		content += "\t\t<id>1</id>\n";
		content += "\t\t<title>Iteration 1</title>\n";
		content += "\t\t<description>des1</description>\n";
		content += "\t\t<duration>1</duration>\n";
		content += "\t\t<deliverable>del1</deliverable>\n";
		content += "\t\t<deadline>2012-01-27</deadline>\n";
		content += "\t\t<person>Person 1</person>\n";
		content += "\t</task>\n";
		
		content += "\t<task>\n";
		content += "\t\t<id>2</id>\n";
		content += "\t\t<title>Iteration 2</title>\n";
		content += "\t\t<description>des2</description>\n";
		content += "\t\t<duration>2</duration>\n";
		content += "\t\t<deliverable>del2</deliverable>\n";
		content += "\t\t<deadline>2012-01-27</deadline>\n";
		content += "\t\t<person>Person 2</person>\n";
		content += "\t</task>\n";
		
		content += "\t<task>\n";
		content += "\t\t<id>3</id>\n";
		content += "\t\t<title>Iteration 3</title>\n";
		content += "\t\t<description>des3</description>\n";
		content += "\t\t<duration>3</duration>\n";
		content += "\t\t<deliverable>del3</deliverable>\n";
		content += "\t\t<deadline>2012-01-27</deadline>\n";
		content += "\t\t<person>Person 1</person>\n";
		content += "\t</task>\n";
		content += "</data>\n";
		
		// create the input xml file 
		createFile(infilename, content);
		
		// load the input xml file (task file) into the task and people tables
		// expect successful loading
		TaskTable taskTable = TaskTable.getInstance();
		PeopleTable peopleTable = PeopleTable.getInstance();
		assertTrue(taskTable.openXMLFile(infilename));
		
		// expect the task table to contain 3 tasks
		// and people table to contain 2 persons as two tasks are assigned the same person 
		assertEquals(taskTable.getTaskList().size(), 3);
		assertEquals(peopleTable.getPersonList().size(), 2);

		// expect the output CSV people file to exist 
		// and verify its content
		assertFalse(fileExists(outFilename));
		assertTrue(peopleTable.saveCSVFile(outFilename));
		assertTrue(fileExists(outFilename));
		
		String cont = loadFileContent(outFilename);
		String expected = "";
		expected += HEADER_STRING ;
		expected += "Person 1,4,\"1, 3\""; 
		expected += "\n";
		expected += "Person 2,2,\"2\""; 
		expected += "\n";
		System.out.println(cont);
		assertTrue(cont.equals(expected));
		
		// clean up
		deleteFile(infilename);
		deleteFile(outFilename);
	}
}
